/*
 * Copyright (C) 2010-2012 Enrique Lara (enrique.posix2.lara@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
 * limitations under the License.
  */
package app.transitalarm;

import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;

import android.content.Context;
import android.content.Intent;

import android.net.Uri;

import android.os.Binder;
import android.os.IBinder;

import android.widget.Toast;

import app.transitalarm.model.Alarm;
import app.transitalarm.model.App;
import app.transitalarm.model.Poller;

import app.transitalarm.util.Constants;
import app.transitalarm.util.Log;

import java.util.HashMap;

public final class PollingService extends Service {
    private static final String TAG = "PollingService";
    NotificationManager notificationMgr;
    private final HashMap<Uri, Poller> pollers = new HashMap<Uri, Poller>(10);

    public PollingService() {
        super();
    }

    @Override
    public void onCreate() {
        notificationMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    }

    @Override
    public void onDestroy() {
        for (final Poller p : pollers.values()) {
            p.stopThread();
            signalEnd(p);
        }

        Toast.makeText(this, R.string.all_polling_cancelled, Toast.LENGTH_LONG).show();
        pollers.clear();
    }

    @Override
    public IBinder onBind(final Intent intent) {
        return mBinder;
    }

    private final IBinder mBinder = new LocalBinder();

    public final class LocalBinder extends Binder {
        PollingService getService() {
            return PollingService.this;
        }
    }

    @Override
    public int onStartCommand(final Intent intent, final int flags, final int startId) {
        final Uri uri = (intent != null) ? intent.getData() : null;

        if (uri != null) {
            if (Constants.ACTION_POLLING.equals(intent.getAction())) {
                runWorkerThread(uri, false);
            } else if (Constants.ACTION_POLLING_ONE_OFF.equals(intent.getAction())) {
                runWorkerThread(uri, true);
            } else if (Constants.ACTION_CANCEL_POLLING.equals(intent.getAction())) {
                stopWorkerThread(uri);
            } else {
                cancelRogue(intent);
            }
        } else {
            cancelRogue(intent);
        }

        return super.onStartCommand(intent, flags, startId);
    }

    void stopWorkerThread(final Uri uri) {
        final Poller p;

        synchronized (pollers) {
            p = pollers.remove(uri);
        }

        if (p != null) {
            p.stopThread();
            signalEnd(p);
        }

        Toast.makeText(this, R.string.polling_cancelled, Toast.LENGTH_SHORT).show();
    }

    public void signalEnd(final Poller poller) {
        synchronized (pollers) {
            pollers.remove(poller.getAlarm().getUri());
            notificationMgr.cancel(poller.getAlarm().getId());
        }
    }

    private void runWorkerThread(final Uri uri, final boolean oneOff) {
        if (uri != null) {
            synchronized (pollers) {
                if (pollers.containsKey(uri)) {
                    Toast.makeText(PollingService.this, "Already Polling:" + uri, Toast.LENGTH_SHORT).show();

                    return;
                }
            }

            final Alarm a = App.loadAlarm(uri, this);

            if (a != null) {
                if (oneOff || a.isActiveToday()) {
                    final Poller p = new Poller(a, this, oneOff);
                    p.startThread();
                    pollers.put(uri, p);

                    if (a.getRepeat() == 0) {
                        a.setEnabled(false);
                        a.update(); //XXX this won't update the UI, app wide event listeners?
                    }
                } else {
                    Log.d(TAG, "Alarm not active today, that's all for now, thanks.");
                }
            } else {
                Toast.makeText(PollingService.this, "Problems Reading Alarm:" + uri, Toast.LENGTH_SHORT).show();
            }
        } else {
            Toast.makeText(PollingService.this, "Received Null Uri", Toast.LENGTH_SHORT).show();
        }
    }

    private void cancelRogue(final Intent intent) {
        if (intent != null) {
            final PendingIntent sender = PendingIntent.getBroadcast(this, 0, intent, 0);
            final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
            am.cancel(sender);
            Toast.makeText(PollingService.this, "Cancelled Errant intent:" + intent, Toast.LENGTH_LONG).show();
        } else {
            Log.d(TAG, "Intent was null and could not be cancelled.");
        }
    }
}
